#! /usr/bin/env python3
# coding:utf-8
import json
import time
import uuid
import hmac
import hashlib
import base64
import requests
from urllib.parse import quote, urlparse, urlunparse, parse_qs
from tornado.options import define, options
import tornado
import urllib3

urllib3.disable_warnings()

define('access_key', default='d8e6f412ab44e633a338d7d0294a289f', help='access key', type=str)
define('access_key_secret', default='5720f2082be065d6e539b2e5c1706f01', help='access key secret', type=str)
define('method', default='POST', help='http请求方法', type=str)
define('url', default='https://cg-sit-union-access.yuntiancloud.com/v3/union/apply?BizId=biz-test', help='请求URL', type=str)
define('signature_version', default='1.1', help='签名算法版本', type=str)
define('signature_nonce', default='', help='指定signature nonce', type=str)
define('timestamp', default='', help='指定ticket过期时间, ticket_timeout无效', type=str)
define('ticket_timeout', default=1000, help='ticket超时时间(ms)', type=int)
define('ticket_nonce', default='', help='指定ticket nonce', type=str)
define('data', default='{"debug_mode":false,"uuid":574423452,"ugid":34765,"dev_type":5,"utoken":"pgo79gvnhevzfjw2","opaque":"","dev_id":"07ea4c4ee2094e37834274edfaf73d5a","os_type":3,"sdk_version":3056003,"join_method":0,"queue_level":0,"rset_id":1,"vmid":9,"apply_mode":0,"account_auth_type":1,"open_token_expired":true,"check_game_state":true,"host_method":0}', help='', type=str)
define('verbose', default=True, help='是否打印详细信息', type=bool)


def get_version():
    if options.signature_version == '1.1':
        return '2020-11-01'

    if options.signature_version == '1.2':
        return '2022-11-04'


def get_timestamp():
    if options.timestamp != '':
        return options.timestamp
    return '{}'.format(int(time.time() * 1000) + options.ticket_timeout)


def get_signature_nonce():
    if options.signature_nonce != '':
        return options.signature_nonce
    return str(uuid.uuid1())


def get_ticket_nonce():
    if options.ticket_nonce != '':
        return options.ticket_nonce
    return str(uuid.uuid1())


def check_auth():
    """
    场景：正常情况
    """
    # 请求公共参数
    request_params = {
        # 'BizId': 'biz-review',
        'Format': 'JSON',
        'Version': get_version(),
        'AccessKey': options.access_key,
        'Timestamp': get_timestamp(),
        'SignatureMethod': 'HMAC-SHA1',
        'SignatureVersion': options.signature_version,
        'SignatureNonce': get_signature_nonce(),
        'Ticket': '',
        'TicketNonce': get_ticket_nonce(),
    }

    access_key_secret = options.access_key_secret

    # 1.2 版本使用ticket作为secret
    if options.signature_version == "1.2":
        string_to_ticket = '{}&{}&{}&{}'.format(request_params['AccessKey'], options.access_key_secret,
                                                request_params['TicketNonce'], request_params['Timestamp'])
        if options.verbose:
            print('[v1.2][0] string_to_ticket:     ', string_to_ticket)

        enc_str = string_to_ticket.encode('utf-8')
        enc_key = (options.access_key_secret + '&').encode('utf-8')
        if options.verbose:
            print('[v1.2][1] enc_key:              ', enc_key, "enc_str:", enc_str)

        ticket = hmac.new(enc_key, enc_str, 'sha1').digest()
        if options.verbose:
            print('[v1.2][2] ticket_befor_base64:  ', ticket)

        request_params['Ticket'] = base64.b64encode(ticket).decode()
        if options.verbose:
            print('[v1.2][3] ticket_after_base64:  ', request_params['Ticket'])

        access_key_secret = request_params['Ticket']

    urlobj = urlparse(options.url)
    for k, v in parse_qs(urlobj.query).items():
        request_params[k] = v[0]
    pure_url = urlunparse((urlobj.scheme, urlobj.netloc, urlobj.path, '', '', ''))

    # 发送请求
    request(pure_url, options.method, request_params, access_key_secret + '&', options.data)


def request(url, method, params, key, data, headers=None):
    """
    增加签名
    :param url: 目标url
    :param params: 参数（类型为dict）
    :return: requests.Response
    """
    urlobj = urlparse(url)
    m = hashlib.md5(data.encode())
    bodymd5 = base64.b64encode(m.digest())
    print('[0] md5:', m.hexdigest(), 'bodymd5:', bodymd5)

    # 计算签名
    encrypt_string = ''
    for param in sorted(params.keys()):
        encrypt_string += ('&' + quote(param.encode()) + '=' + quote(params[param].encode(), safe=''))
    if options.verbose:
        print('[1] canonicalized_query_sString:', encrypt_string[1:])

    signature_string = (
                method + '&' + quote(urlobj.path.encode(), safe='') + '&' + quote(bodymd5, safe='') + '&' + quote(
            encrypt_string[1:].encode(), safe=''))
    if options.verbose:
        print('[2] signature_string:           ', signature_string)
    enc_key = key.encode('utf-8')

    enc_str = signature_string.encode('utf-8')
    if options.verbose:
        print('[3] enc_key:                    ', enc_key, "enc_str:", enc_str)

    signature = hmac.new(enc_key, enc_str, 'sha1').digest()
    if options.verbose:
        print('[4] signature_befor_base64:     ', signature)

    params['Signature'] = base64.b64encode(signature)
    if options.verbose:
        print('[5] signature_after_base64:     ', params['Signature'])

    headers = {'Content-Type': 'application/json'}

    # 发送请求
    print(f"params={params}")
    print(f"data={json.loads(data)}")
    print(f"data={type(json.loads(data))}")
    # r = requests.request(method, url, params=params, headers=headers, data=data.encode('utf-8'), verify=False)
    r = requests.request(method, url, params=params, headers=headers, data=json.loads(data), verify=False)
    print('[6] request url:', r.url)
    if r.status_code != 200:
        print('请求失败：status_code =', r.status_code)
        print(f"resp = {r.text}")
        return
    print(r.text)

    # 下载文件直接返回
    if r.headers['Content-Type'] == 'application/octet-stream':
        return r


if __name__ == '__main__':
    tornado.options.parse_command_line()
    check_auth()
